#ifndef __WIZ_UTILS_FACTORY_TEMPLATE_HPP__SHANHAOBO_19800429__
#define __WIZ_UTILS_FACTORY_TEMPLATE_HPP__SHANHAOBO_19800429__

#include "../../Base/WizBase.hpp"
#include "../../Core/Container/WizDataTypeMap.hpp"
namespace Wiz
{
    namespace Factory
    {
        template<class PID, class Param> class Type;
    } /// end of namespace Factory
} /// end of namespace Wiz

#endif /*__WIZ_UTILS_FACTORY_TEMPLATE_HPP__SHANHAOBO_19800429__*/

#if defined(WIZ_FACTORY_PARAM_COUNT) && (WIZ_FACTORY_PARAM_COUNT >= 0) && (WIZ_FACTORY_PARAM_COUNT < 255)

namespace Wiz
{
    namespace Factory
    {
        namespace WIZ_MPP_COMBINE(Creator, WIZ_FACTORY_PARAM_COUNT)
        {
            template <class BasePtrT, class NewT WIZ_COMMA_IF(WIZ_FACTORY_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_FACTORY_PARAM_COUNT, class T)>
            struct Type
            {
                typedef BasePtrT        tBaseAtomPtr;
                static tBaseAtomPtr CreateInstance(WIZ_ENUM_PARAM_XY(WIZ_FACTORY_PARAM_COUNT, T, A))
                {
                    return new NewT(WIZ_ENUM_PARAM_X(WIZ_FACTORY_PARAM_COUNT, A));
                }
            };
        } /// end of namespace Creator
    } /// end of namespace Factory
} /// end of namespace Wiz

/// Maybe is included multi times : in same one file
namespace Wiz
{
    namespace Factory
    {
        template<class IDT, class BasePtrT WIZ_COMMA_IF(WIZ_FACTORY_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_FACTORY_PARAM_COUNT, class T)>
        class Type<IDT, BasePtrT(WIZ_ENUM_PARAM_X(WIZ_FACTORY_PARAM_COUNT, T))>
        {
        public:
            WIZ_DECLARE_CLASS_THIS(Type);
            typedef IDT             tID;
            typedef BasePtrT        tBaseAtomPtr;
            typedef tBaseAtomPtr (*tCreateInstance)(WIZ_ENUM_PARAM_X(WIZ_FACTORY_PARAM_COUNT, T));
            typedef ::Wiz::Map::Type<tID, tCreateInstance> tCreatorMap;
        public:
            Type()
            {
            }
        public:
            template<class NewT>
            ::Wiz::Bool::Type Register(const tID& InID)
            {
                tCreatorMap::tIterator Found = m_Map.Find(InID);
                if (Found != m_Map.End())
                {
                    return ::Wiz::Bool::False;
                }

                typedef ::Wiz::Factory::WIZ_MPP_COMBINE(Creator,WIZ_FACTORY_PARAM_COUNT)::Type<tBaseAtomPtr, NewT WIZ_COMMA_IF(WIZ_FACTORY_PARAM_COUNT) WIZ_ENUM_PARAM_X(WIZ_FACTORY_PARAM_COUNT, T)> tCreator;
                m_Map.Insert(InID, tCreator::CreateInstance);
                return ::Wiz::Bool::True;
            }
            ::Wiz::Bool::Type Unregister(const tID& ID)
            {
                tCreatorMap::tIterator Found = m_Map.Find(ID);
                if (Found == m_Map.End())
                {
                    return ::Wiz::Bool::False;
                }
                m_Map.Erase(Found);
                return ::Wiz::Bool::True;
            }
        public:
            tBaseAtomPtr Create(const typename tID& ID WIZ_COMMA_IF(WIZ_FACTORY_PARAM_COUNT) WIZ_ENUM_PARAM_XY(WIZ_FACTORY_PARAM_COUNT, T, A))
            {
                tCreatorMap::tIterator Found = m_Map.Find(ID);
                if (Found == m_Map.End())
                {
                    return WIZ_NULLPTR;
                }

                return Found.GetValue()(WIZ_ENUM_PARAM_X(WIZ_FACTORY_PARAM_COUNT, A));
            }
        protected:
            tCreatorMap m_Map;
        };
    } /// end of namespace Factory
} /// end of namespace Wiz

#endif /*#if defined(WIZ_FACTORY_PARAM_COUNT) && (WIZ_FACTORY_PARAM_COUNT >= 0) && (WIZ_FACTORY_PARAM_COUNT < 255)*/
